package cn.edu.neu.vmmigeval.cloud.policy.impl;


import cn.edu.neu.vmmigeval.cloud.entity.Host;
import cn.edu.neu.vmmigeval.cloud.entity.Vm;
import cn.edu.neu.vmmigeval.cloud.policy.MigratedHostPolicy;
import cn.edu.neu.vmmigeval.cloud.util.MathUtil;
import cn.edu.neu.vmmigeval.cloud.util.UtilizationHistoryUtil;

public class MigratedHostPolicyInterQuartileRange extends MigratedHostPolicy {

	/** The safety parameter. */
	private double safetyParameter = 1.2;
	
	public MigratedHostPolicyInterQuartileRange(double safetyParameter){
		super();
		this.safetyParameter = safetyParameter;
	}
	
	public MigratedHostPolicyInterQuartileRange(){
	}	
	
	@Override
	public boolean isHostOverUtilized(Host host) {
		double upperThreshold = 0;
		try {
			//System.out.println(getSafetyParameter());
			//System.out.println( getHostUtilizationIqr(host));
			
			upperThreshold = 1 - getSafetyParameter() * getHostUtilizationIqr(host);
			if(upperThreshold<=0.85||upperThreshold>0.99){
				upperThreshold = 0.9;
			}
			
			//System.out.println("is :"+upperThreshold);
		} catch (IllegalArgumentException e) {
			//return getFallbackVmAllocationPolicy().isHostOverUtilized(host);
		}
		double totalRequestedMips = 0;
		for (Vm vm : host.getVmList()) {
			//totalRequestedMips += vm.getCurrentRequestedTotalMips();
			totalRequestedMips += vm.getCurrentCpu();
		}
		//double utilization = totalRequestedMips / host.getTotalMips();
		double utilization = totalRequestedMips / host.getTotalCpu();
		return utilization > upperThreshold;
	}
	
	/**
	 * Gets the host utilization iqr.
	 * 
	 * @param host the host
	 * @return the host utilization iqr
	 */
	public double getHostUtilizationIqr(Host host) throws IllegalArgumentException {
		double[] data = UtilizationHistoryUtil.getUtilizationHistory(host.getUtilizationHistory());
		if (MathUtil.countNonZeroBeginning(data) >= 12) { // 12 has been suggested as a safe value
			return MathUtil.iqr(data);
		}
		throw new IllegalArgumentException();
	}

	@Override
	public boolean isHostUnderUtilized(Host host) {
		// TODO Auto-generated method stub
		return false;
	}
		
	/**
	 * Sets the safety parameter.
	 * 
	 * @param safetyParameter the new safety parameter
	 */
	protected void setSafetyParameter(double safetyParameter) {
		if (safetyParameter < 0) {
//			Log.printLine("The safety parameter cannot be less than zero. The passed value is: "
//					+ safetyParameter);
			System.exit(0);
		}
		this.safetyParameter = safetyParameter;
	}

	/**
	 * Gets the safety parameter.
	 * 
	 * @return the safety parameter
	 */
	protected double getSafetyParameter() {
		return safetyParameter;
	}
}
